package net.letcode.core.utils.security.up;

import java.io.UnsupportedEncodingException;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;

import org.apache.commons.lang3.StringUtils;

public class SDKUtil {
	private static String charSet = "UTF-8";
	
	protected static char[] letter = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };

	protected static final Random random = new Random();

	public static boolean sign(KeyStore keyStore, String certPwd, Map<String, Object> data) {
		String stringData = coverMap2String(data);
		byte[] byteSign = null;
		String stringSign = null;
		try {
			byte[] signDigest = SecureUtil.sha1X16(stringData);
			byteSign = SecureUtil.base64Encode(SecureUtil.signBySoft(CertUtil.getSignCertPrivateKey(keyStore, certPwd), signDigest));
			stringSign = new String(byteSign);
			data.put("signature", stringSign);
			return true;
		} catch (Exception e) {
			LogUtil.writeErrorLog("签名异常", e);
		}
		return false;
	}

	public static boolean validate(Map<String, X509Certificate> certMap, Map<String, Object> resData) {
		LogUtil.writeLog("验签处理开始.");
		String stringSign = (String) resData.get("signature");

		String certId = (String) resData.get("certId");

		String stringData = coverMap2String(resData);

		try {
			return SecureUtil.validateSignBySoft(CertUtil.getValidateKey(certMap, certId), SecureUtil.base64Decode(stringSign.getBytes(charSet)), SecureUtil.sha1X16(stringData));

		} catch (UnsupportedEncodingException e) {
			LogUtil.writeErrorLog(e.getMessage(), e);
		} catch (Exception e) {
			LogUtil.writeErrorLog(e.getMessage(), e);
		}
		return false;
	}

	public static String coverMap2String(Map<String, Object> data) {
		TreeMap<String, Object> tree = new TreeMap<>();
		Iterator<Map.Entry<String, Object>> it = data.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, Object> en = (Map.Entry<String, Object>) it.next();
			if (!"signature".equals(((String) en.getKey()).trim())) {

				tree.put(en.getKey(), en.getValue());
			}
		}
		it = tree.entrySet().iterator();
		StringBuffer sf = new StringBuffer();
		while (it.hasNext()) {
			Map.Entry<String, Object> en = (Map.Entry<String, Object>) it.next();
			sf.append((String) en.getKey() + "=" + (String) en.getValue() + "&");
		}

		return sf.substring(0, sf.length() - 1);
	}

	public static Map<String, Object> coverResultString2Map(String result) {
		return convertResultStringToMap(result);
	}

	public static Map<String, Object> convertResultStringToMap(String result) {
		Map<String, Object> map = null;
		try {
			if (StringUtils.isNotBlank(result)) {
				if ((result.startsWith("{")) && (result.endsWith("}"))) {
					System.out.println(result.length());
					result = result.substring(1, result.length() - 1);
				}
				map = parseQString(result);
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return map;
	}

	public static Map<String, Object> parseQString(String str) throws UnsupportedEncodingException {
		Map<String, Object> map = new HashMap<>();
		int len = str.length();
		StringBuilder temp = new StringBuilder();

		String key = null;
		boolean isKey = true;
		boolean isOpen = false;
		char openName = '\000';
		if (len > 0) {
			for (int i = 0; i < len; i++) {
				char curChar = str.charAt(i);
				if (isKey) {
					if (curChar == '=') {
						key = temp.toString();
						temp.setLength(0);
						isKey = false;
					} else {
						temp.append(curChar);
					}
				} else {
					if (isOpen) {
						if (curChar == openName) {
							isOpen = false;
						}
					} else {
						if (curChar == '{') {
							isOpen = true;
							openName = '}';
						}
						if (curChar == '[') {
							isOpen = true;
							openName = ']';
						}
					}
					if ((curChar == '&') && (!isOpen)) {
						putKeyValueToMap(temp, isKey, key, map);
						temp.setLength(0);
						isKey = true;
					} else {
						temp.append(curChar);
					}
				}
			}

			putKeyValueToMap(temp, isKey, key, map);
		}
		return map;
	}

	private static void putKeyValueToMap(StringBuilder temp, boolean isKey, String key, Map<String, Object> map) throws UnsupportedEncodingException {
		if (isKey) {
			key = temp.toString();
			if (key.length() == 0) {
				throw new RuntimeException("QString format illegal");
			}
			map.put(key, "");
		} else {
			if (key.length() == 0) {
				throw new RuntimeException("QString format illegal");
			}
			map.put(key, temp.toString());
		}
	}

	public static String decryptCvn2(KeyStore keyStore, String certPwd, String base64cvn2) {
		return SecureUtil.DecryptedData(base64cvn2, CertUtil.getSignCertPrivateKey(keyStore, certPwd));
	}

	public static String decryptAvailable(KeyStore keyStore, String certPwd, String base64Date) {
		return SecureUtil.DecryptedData(base64Date, CertUtil.getSignCertPrivateKey(keyStore, certPwd));
	}

	public static String decryptPan(KeyStore keyStore, String certPwd, String base64Pan) {
		return SecureUtil.DecryptedData(base64Pan, CertUtil.getSignCertPrivateKey(keyStore, certPwd));
	}

	public static String encryptTrack(String trackData, String modulus, String exponent) {
		return SecureUtil.EncryptData(trackData, CertUtil.getEncryptTrackCertPublicKey(modulus, exponent));
	}

	public static boolean isEmpty(String s) {
		return (null == s) || ("".equals(s.trim()));
	}

	public static String generateTxnTime() {
		return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
	}

	public static String generateOrderId() {
		StringBuilder sb = new StringBuilder();
		int len = random.nextInt(18);
		for (int i = 0; i < len; i++) {
			sb.append(letter[i]);
		}
		return generateTxnTime() + sb.toString();
	}

	public static String createAutoSubmitForm(String url, Map<String, Object> data) {
		StringBuffer sf = new StringBuffer();
		sf.append("<form id = \"sform\" action=\"" + url + "\" method=\"post\">");

		if ((null != data) && (0 != data.size())) {
			Set<Map.Entry<String, Object>> set = data.entrySet();
			Iterator<Map.Entry<String, Object>> it = set.iterator();
			while (it.hasNext()) {
				Map.Entry<String, Object> ey = (Map.Entry<String, Object>) it.next();
				String key = (String) ey.getKey();
				String value = (String) ey.getValue();
				sf.append("<input type=\"hidden\" name=\"" + key + "\" id=\"" + key + "\" value=\"" + value + "\"/>");
			}
		}

		sf.append("</form>");
		sf.append("</body>");
		sf.append("<script type=\"text/javascript\">");
		sf.append("document.getElementById(\"sform\").submit();\n");
		sf.append("</script>");
		return sf.toString();
	}

	public static void main(String encryptTrackCertPath, String[] args) {
		System.out.println(encryptTrack(encryptTrackCertPath, "12", "utf-8"));
	}
}